#include "ser.h"
 
// mysqlclient
bool mysql_client::mysql_ConnectServer()
{
    MYSQL *mysql = mysql_init(&mysql_con);
    if (mysql == NULL)
    {
        return false;
    }
 
    mysql = mysql_real_connect(mysql, db_ips.c_str(), db_username.c_str(), db_passwd.c_str(), db_dbname.c_str(), 3306, NULL, 0);
    if (mysql == NULL)
    {
        cout << "connect db server err" << endl;
        return false;
    }
 
    return true;
}
bool mysql_client::mysql_Register(const string &tel, const string &passwd, const string &name)
{
    // insert into user_info values(0,'13200000000','小王','123456',1);
    string sql = string("insert into user_info values(0,'") + tel + string("','") + name + string("','") + passwd + string("',1)");
    if (mysql_query(&mysql_con, sql.c_str()) != 0)
    {
        return false;
    }
 
    return true;
}
 
bool mysql_client::mysql_Login(const string &tel, const string &passwd,string &name)
{
    // select username,passwd from user_info where tel=13400000000;
    string sql1 = string("select username,passwd from user_info where tel=") + tel;
    if (mysql_query(&mysql_con, sql1.c_str()) != 0)
    {
        cout<<2<<endl;
        return false;
    }
 
    MYSQL_RES *r = mysql_store_result(&mysql_con); // 获取结果集
    if (r == NULL)
    {
         cout<<3<<endl;
        return false;
    }
 
    int num = mysql_num_rows(r); // 获取结果集有多少行，0行就是为查询到，意味着该用户没有注册
    if (num == 0)
    {
        mysql_free_result(r);
        return false;
    }
 
    MYSQL_ROW row = mysql_fetch_row(r);
 
    string password = row[1];
 
    if (password.compare(passwd) != 0)
    {
        mysql_free_result(r);
        return false;
    }
 
    name = row[0];
    mysql_free_result(r);
    return true;
}
 
bool mysql_client::mysql_Show_Ticket(Json::Value &resval)
{
    string sql = "select tk_id,addr,max,num ,use_date from ticket_info";
    if (mysql_query(&mysql_con, sql.c_str()) != 0)
    {
        cout << "show ticket err" << endl;
        return false;
    }
 
    MYSQL_RES *r = mysql_store_result(&mysql_con);
    if (r == NULL)
    {
        return false;
    }
 
    int n = mysql_num_rows(r);
    if (n == 0)
    {
        resval["status"] = "OK";
        resval["num"] = 0;
        return true;
    }
 
    resval["status"] = "OK";
    resval["num"] = n;
 
    for (int i = 0; i < n; i++)
    {
        MYSQL_ROW row = mysql_fetch_row(r);
        Json::Value tmp;
        tmp["tk_id"] = row[0];
        tmp["add"] = row[1];
        tmp["max"] = row[2];
        tmp["num"] = row[3];
        tmp["use_date"] = row[4];
        resval["arr"].append(tmp);
    }
 
    return true;
}
 
bool mysql_client::mysql_user_begin()
{
    if (mysql_query(&mysql_con, "begin") != 0)
    {
        cout<< 1 << endl;
        return false;
    }
    return true;
}
bool mysql_client::mysql_user_commit()
{
    if (mysql_query(&mysql_con, "commit") != 0)
    {
        return false;
    }
    return true;
}
bool mysql_client::mysql_user_rollback()
{
    if (mysql_query(&mysql_con, "rollback") != 0)
    {
        return false;
    }
    return true;
}
bool mysql_client::mysql_Subscribe_Ticket(int tk_id, string tel)
{
    mysql_user_begin(); // 启动事务
    string s1 = string("select max,num from ticket_info where tk_id =") + to_string(tk_id);
    if (mysql_query(&mysql_con, s1.c_str()) != 0)
    {
        cout << "查询max,num失败" << endl;
        mysql_user_rollback();
        return false;
    }
 
    MYSQL_RES *r = mysql_store_result(&mysql_con);
    if (r == NULL)
    {
        cout << "获取结果集失败" << endl;
        mysql_user_rollback();
        return false;
    }
 
    int Num = mysql_num_rows(r);
    if (Num != 1)
    {
        cout << "记录行不为一" << endl;
        mysql_user_rollback();
        return false;
    }
 
    MYSQL_ROW row = mysql_fetch_row(r);
    string str_max = row[0]; // 总票数
    string str_num = row[1]; // 当前已定票数
    int tk_max = atoi(str_max.c_str());
    int tk_num = atoi(str_num.c_str());
    if (tk_max <= tk_num)
    {
        cout << "没有可用的票" << endl;
        mysql_user_rollback();
        return false;
    }
 
    tk_num++;
    // update ticket_info set num=3 where tk_id=1;
    string s2 = string("update ticket_info set num=") + to_string(tk_num) + string(" where tk_id=") + to_string(tk_id);
    if (mysql_query(&mysql_con, s2.c_str()) != 0)
    {
        cout << "修改预订票数失败" << endl;
        mysql_user_rollback();
        return false;
    }
 
    // sub_ticket
    // insert into sub_ticket values(0,1,'1350000000',now());
    string s3 = string("insert into sub_ticket values(0,") + to_string(tk_id) + string(",'") + tel + string("',now())");
    if (mysql_query(&mysql_con, s3.c_str()) != 0)
    {
        cout << "存入预订信息失败" << endl;
        mysql_user_rollback();
        return false;
    }
 
    mysql_user_commit();
    return true;
}
 
// socket_listen
bool socket_listen::socket_init()
{
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        return false;
    }
 
    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(m_port);
    saddr.sin_addr.s_addr = inet_addr(m_ips.c_str());
 
    int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
    if (-1 == res)
    {
        cout << "bind err" << endl;
        close(sockfd);
        return false;
    }
 
    res = listen(sockfd, LIS_MAX);
    if (-1 == res)
    {
        return false;
    }
 
    return true;
}
int socket_listen::accept_client()
{
    int c = accept(sockfd, NULL, NULL);
    return c;
}
 
//---socket_con
 
void socket_con::Send_err()
{
    Json::Value res_val;
    res_val["status"] = "ERR";
    send(c, res_val.toStyledString().c_str(), strlen(res_val.toStyledString().c_str()), 0);
}
void socket_con::Send_ok()
{
    Json::Value res_val;
    res_val["status"] = "OK";
    send(c, res_val.toStyledString().c_str(), strlen(res_val.toStyledString().c_str()), 0);
}
 
/***
 *
 */
 
void socket_con::User_Register()
{
    string tel, passwd, username;
    tel = val["user_tel"].asString();
    passwd = val["user_passwd"].asString();
    username = val["user_name"].asString();
 
    if (tel.empty() || passwd.empty() || username.empty())
    {
        Send_err();
    }
 
    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err();
        return;
    }
 
    if (!cli.mysql_Register(tel, passwd, username))
    {
        Send_err();
        return;
    }
 
    Send_ok();
    return;
}
void socket_con::User_Login()
{
    string tel = val["user_tel"].asString();
    string passwd = val["user_passwd"].asString();
    string user_name;
 
    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
         cout<<4<<endl;
        Send_err();
        return;
    }
 
    if (!cli.mysql_Login(tel, passwd,user_name))
    {
         cout<<5<<endl;
        Send_err();
        return;
    }
 
    Json::Value res_val;
    res_val["status"] = "OK";
    res_val["user_name"] = user_name;
    send(c, res_val.toStyledString().c_str(), strlen(res_val.toStyledString().c_str()), 0);
    return;
}
 
void socket_con::User_Show_Ticket()
{
    Json::Value resval;
    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err();
        return;
    }
 
    if (!cli.mysql_Show_Ticket(resval))
    {
        Send_err();
        return;
    }
 
    send(c, resval.toStyledString().c_str(), strlen(resval.toStyledString().c_str()), 0);
    return;
}
 
void socket_con::User_Subscribe_Ticket()
{
    // client  -> tk_id, tel
    int tk_id = val["index"].asInt();
    string tel = val["tel"].asString();
 
    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        cout << "connect mysql err" << endl;
        Send_err();
        return;
    }
 
    if (!cli.mysql_Subscribe_Ticket(tk_id, tel))
    {
        Send_err();
        return;
    }
 
    Send_ok();
    return;
}
 
void socket_con::User_Show_Sub_Ticket()
{
    string tel = val["user_tel"].asString();

    mysql_client cli;
    if (!cli.mysql_ConnectServer())
    {
        Send_err();
        return;
    }

    // 构建查询语句，查询该用户的所有预约记录
    string sql = string("SELECT st.tk_id, ti.addr, ti.max, ti.num, ti.use_date FROM sub_ticket st ")
                 + "JOIN ticket_info ti ON st.tk_id = ti.tk_id WHERE st.tel = '" + tel + "'";

    if (mysql_query(&cli.mysql_con, sql.c_str()) != 0)
    {
        Send_err();
        return;
    }

    MYSQL_RES *r = mysql_store_result(&cli.mysql_con);
    if (r == NULL)
    {
        Send_err();
        return;
    }

    int n = mysql_num_rows(r);
    Json::Value resval;
    if (n == 0)
    {
        resval["status"] = "OK";
        resval["num"] = 0;
    }
    else
    {
        resval["status"] = "OK";
        resval["num"] = n;

        for (int i = 0; i < n; i++)
        {
            MYSQL_ROW row = mysql_fetch_row(r);
            Json::Value tmp;
            tmp["tk_id"] = row[0];
            tmp["add"] = row[1];
            tmp["max"] = row[2];
            tmp["num"] = row[3];
            tmp["use_date"] = row[4];
            resval["arr"].append(tmp);
        }
    }

    mysql_free_result(r);
    send(c, resval.toStyledString().c_str(), strlen(resval.toStyledString().c_str()), 0);
    
}

void socket_con::User_Cancel_Sub_Ticket()
{

}
 
void socket_con::Recv_data()
{
    char buff[256] = {0};
    int n = recv(c, buff, 255, 0);
    if (n <= 0)
    {
        cout << "client close" << endl;
        delete this;
        return;
    }
 
    // 测试
    cout << "recv:" << buff << endl;
 
    Json::Reader Read;
    if (!Read.parse(buff, val))
    {
        cout << "Recv_data:解析json失败" << endl;
        Send_err();
        return;
    }
 
    int ops = val["type"].asInt();
    // DL = 1, ZC,CKYY,YD,CKYD,QXYD,TC
    switch (ops)
    {
    case DL:
        User_Login();
        break;
    case ZC:
        User_Register();
        break;
    case CKYY:
        User_Show_Ticket();
        break;
    case YD:
        User_Subscribe_Ticket();
        break;
    case CKYD:
        User_Show_Sub_Ticket();
        break;
    case QXYD:
        User_Cancel_Sub_Ticket();
        break;
    default:
        break;
    }
    // 解析
}
 
// callback
void SOCK_CON_CALLBACK(int fd, short ev, void *arg)
{
    socket_con *q = (socket_con *)arg;
 
    if (ev & EV_READ)
    {
        q->Recv_data();
    }
}
 
void SOCK_LIS_CALLBACK(int sockfd, short ev, void *arg)
{
    socket_listen *p = (socket_listen *)arg;
    if (p == NULL)
    {
        return;
    }
 
    if (ev & EV_READ) // 处理读事件
    {
        int c = p->accept_client();
        if (c == -1)
        {
            return;
        }
 
        cout << "accept : c=" << c << endl;
 
        socket_con *q = new socket_con(c);
 
        struct event *c_ev = event_new(p->Get_base(), c, EV_READ | EV_PERSIST, SOCK_CON_CALLBACK, q);
        if (c_ev == NULL)
        {
            close(c);
            delete q;
            return;
        }
        q->Set_ev(c_ev);
        // 添加到libevent
        event_add(c_ev, NULL);
    }
}
int main()
{
    // 监听套接字
    socket_listen sock_ser;
    if (!sock_ser.socket_init())
    {
        cout << "socket init err" << endl;
        exit(1);
    }
 
    // 创建lievent base
    struct event_base *base = event_init();
    if (base == NULL)
    {
        cout << "base null" << endl;
        exit(1);
    }
 
    // 设置socket_listen中的libevent的base
    sock_ser.Set_base(base);
    // 添加sockfd到libevent
    struct event *sock_ev = event_new(base, sock_ser.Get_sockfd(), EV_READ | EV_PERSIST, SOCK_LIS_CALLBACK, &sock_ser);
    event_add(sock_ev, NULL);
    // 启动事件循环
    event_base_dispatch(base); // select poll epoll
 
    // 释放资源
    event_free(sock_ev);
    event_base_free(base);
}
